package com.freedom.web.mymvc.pool;

import java.lang.reflect.Method;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;

import com.freedom.web.mymvc.route.RouteBuilder;
import com.freedom.web.mymvc.route.Route;
import com.freedom.web.mymvc.utils.ByteBufUtils;
import com.freedom.web.mymvc.utils.LoggerUtils;
import com.freedom.web.mymvc.utils.ConstantsUtils;
import com.freedom.web.mymvc.utils.NettyUtils;
import com.freedom.web.mymvc.utils.UriUtils;
import com.freedom.web.mymvc.utils.ViewType;
import com.freedom.web.mymvc.view.ModelAndView;
import com.freedom.web.mymvc.view.velocity.MyVelocityEngine;
import com.freedom.web.mymvc.view.velocity.MyVelocityWriter;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus;

import static io.netty.handler.codec.http.HttpHeaders.Names.*;

public class MyMVCRunnable implements Runnable {
	// logger
	private static final Logger logger = LogManager.getLogger(MyMVCRunnable.class);
	// 保存变量
	private ChannelHandlerContext context;
	private FullHttpRequest request;
	private FullHttpResponse response;

	public MyMVCRunnable(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse resp) {
		context = ctx;
		request = req;
		response = resp;
	}

	@Override
	public void run() {
		// 当前在第3层的线程池里
		// 根据URI来查找object.method.invoke
		String uri = UriUtils.parseUri(request.getUri());
		LoggerUtils.debug(logger, "uri---" + uri + " length:" + uri.length());
		// 2)寻找路由失败
		Route route = RouteBuilder.getInstance().getRoute(uri);
		if (null == route) {
			request = null;
			response = null;
			NettyUtils.sendError(context, HttpResponseStatus.NOT_FOUND);
			return;
		}
		// 3)寻找路由成功了
		Object obj = route.getObject();
		Method method = route.getMethod();
		try {
			Object invokedResult = method.invoke(obj, request, response);
			ModelAndView modelAndView = (null != invokedResult) ? (ModelAndView) invokedResult : null;
			LoggerUtils.debug(logger, "get modelandview succeed...");
			viewResolve(modelAndView);
		} catch (Exception e) {
			LoggerUtils.error(logger, e.toString());
			request = null;
			response = null;
			NettyUtils.sendError(context, HttpResponseStatus.SERVICE_UNAVAILABLE);
			return;
		}
		// 结束
	}

	private void viewResolve(ModelAndView modelAndView) throws Exception {
		// 开始渲染
		boolean needToViewResolve = (null != modelAndView);
		boolean isKeepAlive = HttpHeaders.isKeepAlive(request);
		// 1)如果要渲染，则构造新的content
		if (needToViewResolve) {
			// 1.1)获取相应的参数
			ViewType type = modelAndView.getType();
			Object model = modelAndView.getModel();
			String view = modelAndView.getView();
			LoggerUtils.debug(logger,
					"type: " + type + " model: " + model + " view: " + view//
							+ " needToViewReslove: " + needToViewResolve//
							+ " isKeepAlive: " + isKeepAlive//
			);

			// 1.2)构造response的body部分
			LoggerUtils.debug(logger, "need to rolve view template: " + view);
			String body = "";
			if (type == ViewType.VELOCITY) {// velocity模板
				MyVelocityWriter writer = new MyVelocityWriter();
				MyVelocityEngine.getInstance().mergeTemplate(view.trim(), "UTF-8", (VelocityContext) model, writer);
				// 获取渲染后的内容
				body = writer.getBody();
			} else {// 其它TODO

			}
			ByteBuf buffer = Unpooled.copiedBuffer(body.getBytes("UTF-8"));
			response.content().writeBytes(buffer);
			buffer.release();
		}

		// 2)构造header部分
		if (needToViewResolve) {// 如果需要渲染，强制设置为HTML,否则由用户自己指定类型
			response.headers().set(CONTENT_TYPE, ConstantsUtils.HTML);
			// 需要渲染时,不缓存
			response.headers().set(EXPIRES, "Thu, 01-Jan-1970 00:00:00 GMT");
		}
		response.headers().set(CONNECTION, isKeepAlive ? HttpHeaders.Values.KEEP_ALIVE : HttpHeaders.Values.CLOSE);
		response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
		response.headers().set(SERVER, ConstantsUtils.SERVER);
		// 3)最终可以发送了
		// http://www.cnblogs.com/Binhua-Liu/p/5295365.html
		// 根据此文章，线程安全，所以可以直接写
		ChannelFuture future = context.writeAndFlush(response);
		if (!isKeepAlive) {
			future.addListener(ChannelFutureListener.CLOSE);
		}
		// 结束 :)
	}
}
